package org.dru.clay.util.functional;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * AbstractIterator
 * User: joakimd
 * Date: 2013-07-24
 * Time: 14:25
 */
public abstract class AbstractIterator<T> implements Iterator<T> {
    private State state;
    private T next;

    protected AbstractIterator() {
        state = State.NOT_READY;
        next = null;
    }

    @Override
    public boolean hasNext() {
        switch (state) {
            case ERROR:
                throw new Error("error");
            case READY:
                return true;
            case DONE:
                return false;
            case NOT_READY:
                setError();
                next = computeNext();
                if (state != State.DONE) {
                    setReady();
                    return true;
                }
                return false;
            default:
                throw new Error("unhandled state: " + state);
        }
    }

    @Override
    public T next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        setNotReady();
        return next;
    }

    protected final void setNotReady() {
        state = State.NOT_READY;
    }

    protected final void setReady() {
        state = State.READY;
    }

    protected final T setDone() {
        state = State.DONE;
        return null;
    }

    protected final void setError() {
        state = State.ERROR;
    }

    protected abstract T computeNext();

    private static enum State {
        NOT_READY,
        READY,
        DONE,
        ERROR
    }
}
